package cn.com.sbell.vss.csg.vap.util;
import java.util.Collections;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import cn.com.sbell.vss.Util;
import cn.com.sbell.vss.VssConstants;
import cn.com.sbell.vss.csg.vap.bean.PtzCompeteControlInfo;
import cn.com.sbell.vss.csg.vsclient.util.PropertiesHolder;

public class PTZMonitor {
	private final static Log log = LogFactory.getLog(PTZMonitor.class);
	private HttpClient httpClient;
	private String csgUrl;
	private long timeout;
	 
	private Timer scanner;
	private Map controlPTZMap;
	
	
	public PTZMonitor() {
		super();
		
	}
	public void init(){
		scanner=new Timer(true);
		controlPTZMap=Collections.synchronizedMap(new HashMap());
	}
	public void destroy(){
		scanner.cancel();
	}
	public void updateControl(PropertiesHolder holder,String sessionId){
		if(timeout<=0){
			return;
		}
		String clientType=holder.getStrProperty("clientType");
		String cmd=holder.getStrProperty("cmd");
		String deviceId=holder.getStrProperty("vsDeviceId");
		int ptzId=holder.getIntProperty("ptzId");
		PTZInfo info=new PTZInfo(deviceId,ptzId);
//		remove and cancel first
		STOPTask task=(STOPTask)controlPTZMap.remove(info);
		if(null!=task){
			task.cancel();
		}
		if(VssConstants.PTZ_STOP_COMMANDS.contains(cmd)||
				VssConstants.PTZ_AUTO_START.equals(cmd)||
				VssConstants.PTZ_AUTO_STOP.equals(cmd)){
			if(null!=task){
//				all stop from vau has no param, so always not equal
				if(!task.ptzInfo.lastCommand.equals(holder.getStrProperty("param"))){
//					use present sessionId to send
					task.ptzInfo.sessionId=sessionId;
					sendSTOP(task.ptzInfo,task.ptzInfo.stop);
				}
				
			}
			if(VssConstants.PTZ_AUTO_STOP.equals(cmd)){
				fillPTZInfo(holder, sessionId, "TU", info);
				sendSTOP(info,"TU");
				sendSTOP(info,VssConstants.PTZ_STOP);
			}		
		}else if(VssConstants.PTZ_M_COMMANDS.contains(cmd)){
			processCommand(holder, sessionId, cmd, info, 
					task,VssConstants.PTZ_M_COMMANDS,clientType,"STOP");			
			
		}else if(VssConstants.PTZ_F_COMMANDS.contains(cmd)){
			processCommand(holder, sessionId, cmd, info, 
					task,VssConstants.PTZ_F_COMMANDS,clientType,"FST");
			
		}else if(VssConstants.PTZ_I_COMMANDS.contains(cmd)){
			processCommand(holder, sessionId, cmd, info, 
					task,VssConstants.PTZ_I_COMMANDS,clientType,"IST");
			
		}else if(VssConstants.PTZ_Z_COMMANDS.contains(cmd)){
			processCommand(holder, sessionId, cmd, info, 
					task,VssConstants.PTZ_Z_COMMANDS,clientType,"IST");
			
		}
	}
	private void processCommand(PropertiesHolder holder, String sessionId,
			String cmd, PTZInfo info, STOPTask task,Set currentMap,String clientType,String stop) {
		if(null==task){
//			null task should not go to next branches
		}else if(!currentMap.contains(task.ptzInfo.lastCommand)){
//			here only process different lastCmd, same cmd is ignored
//			and use current sessionId to send
			task.ptzInfo.sessionId=sessionId;
			sendSTOP(task.ptzInfo,task.ptzInfo.stop);
		}		
		if(VssConstants.USER_TYPE_VAU.equals(clientType)){
			fillPTZInfo(holder, sessionId, cmd, info);
//			record to be send stop
			info.stop=stop;
			task=new STOPTask(info);
			scanner.schedule(task, timeout);
			controlPTZMap.put(info, task);
		}
	}

	private void fillPTZInfo(PropertiesHolder holder, String sessionId,
			String cmd, PTZInfo info) {
		info.lastCommand=cmd;
		info.speed=holder.getStrProperty("speed");
		info.protocol=holder.getStrProperty("protocol");
		info.userLevel=holder.getStrProperty("userLevel");
		if(Util.strIsNull(info.userLevel)){
			info.userLevel=String.valueOf(PtzCompeteControlInfo.DEFAULT_USERLEVEL);
		}
		info.controlPTZType=holder.getStrProperty("controlPTZType");
		if(Util.strIsNull(info.controlPTZType)){
			info.controlPTZType=String.valueOf(PtzCompeteControlInfo.DEFAULT_CONTROLPTZTYPE);
		}
		info.timePieceLen=holder.getStrProperty("timePieceLen");
		if(Util.strIsNull(info.timePieceLen)){
			info.timePieceLen=String.valueOf(PtzCompeteControlInfo.DEFAULT_TIMEPIECELEN);
		}
		info.vsLoginUsername=holder.getStrProperty("vsLoginUsername");
		info.vsLoginPassword=holder.getStrProperty("vsLoginPassword");
		info.vsVendor=holder.getStrProperty("vsVendor");
		info.username=holder.getStrProperty("__username");
		info.password=holder.getStrProperty("__password");
		info.sessionId=sessionId;
		info.clientType=holder.getStrProperty("clientType");
		if(Util.strIsNull(info.clientType)){
			info.clientType="2";
		}
	}
	
	class STOPTask extends TimerTask{
		PTZInfo ptzInfo;		
		public STOPTask(PTZInfo ptzInfo) {
			super();
			this.ptzInfo = ptzInfo;
		}

		@Override
		public void run() {
			// TODO Auto-generated method stub
			try {
				controlPTZMap.remove(ptzInfo);
				sendSTOP(ptzInfo,ptzInfo.stop);
			} catch (Exception e) {
				// TODO: handle exception
				log.warn("task execution exception", e);
			}
		}
	}
	class PTZInfo{
		public String deviceId;
		public int ptzId;
		public String lastCommand;
		public String stop;
		public String speed;
		public String protocol;
		public String userLevel;
		public String controlPTZType;
		public String timePieceLen;
		public String vsLoginUsername;
		public String vsLoginPassword;
		public String vsVendor;
		public String username;
		public String password;
		public String sessionId;
		public String clientType;
		
		public PTZInfo(String deviceId, int ptzId) {
			super();
			this.deviceId = deviceId;
			this.ptzId = ptzId;
		}
		
		public PTZInfo(String deviceId, int ptzId, String speed,
				String protocol, String userLevel, String controlPTZType,
				String timePieceLen, String vsLoginUsername,
				String vsLoginPassword, String vsVendor, String username,
				String password, String vsIp, String vsPort,String userId,String clientType) {
			super();
			this.deviceId = deviceId;
			this.ptzId = ptzId;
			this.speed = speed;
			this.protocol = protocol;
			this.userLevel = userLevel;
			this.controlPTZType = controlPTZType;
			this.timePieceLen = timePieceLen;
			this.vsLoginUsername = vsLoginUsername;
			this.vsLoginPassword = vsLoginPassword;
			this.vsVendor = vsVendor;
			this.username = username;
			this.password = password;
			this.clientType=clientType;
		}

		@Override
		public boolean equals(Object obj) {
			// TODO Auto-generated method stub
			if(this==obj){
				return true;
			}
			if(!(obj instanceof PTZInfo)){
				return false;
			}
			PTZInfo p=(PTZInfo)obj;
			return deviceId.equals(p.deviceId)&&(ptzId==p.ptzId);
		}
		@Override
		public int hashCode() {
			// TODO Auto-generated method stub
			return deviceId.hashCode()+23*ptzId;
		}
		
	}
	public HttpClient getHttpClient() {
		return httpClient;
	}
	public void setHttpClient(HttpClient httpClient) {
		this.httpClient = httpClient;
	}
	public String getCsgUrl() {
		return csgUrl;
	}
	public void setCsgUrl(String csgUrl) {
		this.csgUrl = csgUrl;
	}

	public long getTimeout() {
		return timeout;
	}

	public void setTimeout(long timeout) {
		this.timeout = timeout;
	}
//	private void sendSTOP(PTZInfo ptzInfo) {
//		sendSTOP(ptzInfo,VssConstants.PTZ_STOP);
//	}
	private void sendSTOP(PTZInfo ptzInfo,String cmd) {
		
		PostMethod pm=new PostMethod(csgUrl);
		try {
		pm.addRequestHeader("Cookie", "sessionId="+ptzInfo.sessionId);
		pm.addParameter("vsLoginUsername", ptzInfo.vsLoginUsername);
		pm.addParameter("vsLoginPassword",ptzInfo.vsLoginPassword);
		pm.addParameter("vsVendor", ptzInfo.vsVendor);
		pm.addParameter("__username", ptzInfo.username);
		pm.addParameter("__password", ptzInfo.password);
		pm.addParameter("ptzId", String.valueOf(ptzInfo.ptzId));
		pm.addParameter("cmd", cmd);
		pm.addParameter("param", ptzInfo.lastCommand);
		pm.addParameter("speed", ptzInfo.speed);
		pm.addParameter("controlPTZType",ptzInfo.controlPTZType);
		pm.addParameter("protocol",ptzInfo.protocol);
		pm.addParameter("timePieceLen", "1");
		pm.addParameter("userLevel", ptzInfo.userLevel);
		pm.addParameter("vsDeviceId", ptzInfo.deviceId);
		pm.addParameter("clientType", ptzInfo.clientType);
		pm.addParameter("ignore",VssConstants.IGNORE_UPDATE);
//		add param can also generate error
			httpClient.executeMethod(pm);
			
		} catch (Exception e) {
			// TODO: handle exception
			log.warn("stop dvs failed"+ptzInfo.deviceId, e);
		}finally{
			pm.releaseConnection();
			log.debug("send out STOP");
		}
	}
	
	
	
}
